package cn.shopifymall.camunda717.service.impl;

import cn.shopifymall.camunda717.api.ProcessApi;
import cn.shopifymall.camunda717.entity.WkflTaskEntity;
import cn.shopifymall.camunda717.service.WkflTaskService;
import cn.shopifymall.camunda717.service.WorkflowService;
import cn.shopifymall.camunda717.vo.OperationVo;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import org.apache.commons.lang3.StringUtils;
import org.camunda.bpm.engine.IdentityService;
import org.camunda.bpm.engine.RepositoryService;
import org.camunda.bpm.engine.RuntimeService;
import org.camunda.bpm.engine.TaskService;
import org.camunda.bpm.engine.delegate.DelegateTask;
import org.camunda.bpm.engine.identity.User;
import org.camunda.bpm.engine.task.IdentityLink;
import org.camunda.bpm.model.bpmn.BpmnModelInstance;
import org.camunda.bpm.model.bpmn.instance.*;
import org.camunda.bpm.model.xml.impl.instance.DomElementImpl;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

import java.util.*;

/**
 * @Author 孤风雪影
 * @Email gitee.com/efairy520
 * @Date 2024/5/15 0:23
 * @Version 1.0
 */
@Service
public class WorkflowServiceImpl implements WorkflowService {

    @Autowired
    private WkflTaskService wkflTaskService;

    @Autowired
    private TaskService taskService;

    @Autowired
    private IdentityService identityService;

    @Autowired
    private RepositoryService repositoryService;

    @Autowired
    private RuntimeService runtimeService;

    @Transactional
    @Override
    public void syncDataWhenTaskCreate(DelegateTask taskDelegate) {
        OperationVo operationVo = ProcessApi.operationVoHolder.get();
        ProcessApi.operationVoHolder.remove();
        if ("rejectBack".equals(operationVo.getOperationType()) || "pointBack".equals(operationVo.getOperationType())) {
            syncTaskByRejectBackOrPointBack(taskDelegate, operationVo);
            return;
        }
        if ("doRetrieve".equals(operationVo.getOperationType())) {
            syncTaskByDoRetrieve(taskDelegate, operationVo);
            return;
        }
        if (StringUtils.isNotBlank(taskDelegate.getAssignee())) {
            //有处理人，说明是指定审批，同步这一条任务即可
            //如果是退回驳回，需要更换处理人

            WkflTaskEntity wkflTaskEntity = new WkflTaskEntity();
            wkflTaskEntity.setAssignee(taskDelegate.getAssignee());
            wkflTaskEntity.setSrcId(operationVo.getTaskId());
            copyTask(taskDelegate, wkflTaskEntity);
            wkflTaskService.save(wkflTaskEntity);

            //将assignee移入候选人,统一使用候选模式
            taskDelegate.addCandidateUser(taskDelegate.getAssignee());
            taskDelegate.setAssignee(null);

            //自动转授权
            autoEntrust(wkflTaskEntity);
        } else {
            //获取自定义属性
            BpmnModelInstance bpmnModelInstance = repositoryService.getBpmnModelInstance(taskDelegate.getProcessDefinitionId());
            UserTask userTask = bpmnModelInstance.getModelElementById(taskDelegate.getTaskDefinitionKey());

            //获取扩展属性
            /*
            ExtensionElements extensionElements = userTask.getExtensionElements();
            Collection<CamundaProperty> properties = extensionElements.getElementsQuery()
                    .filterByType(CamundaProperties.class)
                    .singleResult()
                    .getCamundaProperties();
            for (CamundaProperty property : properties) {
                String name = property.getCamundaName();
                System.out.println(name);
                String value = property.getCamundaValue();
                System.out.println(value);
            }
            */

            DomElementImpl domElement = (DomElementImpl) userTask.getDomElement();
            String ruleId = domElement.getAttribute("http://camunda.org/schema/1.0/bpmn", "ruleId");
            String roleId = "";
            if (StringUtils.isNotBlank(ruleId) && "fetchByRoleId".equals(ruleId)) {
                roleId = domElement.getAttribute("http://camunda.org/schema/1.0/bpmn", "roleId");
            }

            //先根据审批模式，补充业务系统候选人————callRemoteToFetchCandidates
            taskDelegate.addCandidateUser("zhufan183");
            taskDelegate.addCandidateUser("liuyang632");
            taskDelegate.addCandidateUser("yanghua987");

            //查询候选人，包括候选组
            Set<String> candidates = getCandidates(taskDelegate.getId());
            for (String candidate : candidates) {
                WkflTaskEntity wkflTaskEntity = new WkflTaskEntity();
                wkflTaskEntity.setAssignee(candidate);
                wkflTaskEntity.setSrcId(operationVo.getTaskId());
                copyTask(taskDelegate, wkflTaskEntity);
                wkflTaskService.save(wkflTaskEntity);
                //自动转授权
                autoEntrust(wkflTaskEntity);
            }

        }
    }

    private void syncTaskByDoRetrieve(DelegateTask taskDelegate, OperationVo operationVo) {
        WkflTaskEntity taskEntity = wkflTaskService.getById(operationVo.getTaskId());
        WkflTaskEntity newTaskEntity = new WkflTaskEntity();
        newTaskEntity.setAssignee(taskEntity.getAssignee());
        newTaskEntity.setSrcId(operationVo.getTaskId());
        copyTask(taskDelegate, newTaskEntity);
        newTaskEntity.setName(taskEntity.getName());
        wkflTaskService.save(newTaskEntity);

        //将assignee移入候选人,统一使用候选模式
        taskDelegate.addCandidateUser(taskEntity.getAssignee());
        taskDelegate.setAssignee(null);

        //自动转授权
        autoEntrust(newTaskEntity);
    }

    private void syncTaskByRejectBackOrPointBack(DelegateTask taskDelegate, OperationVo operationVo) {
        WkflTaskEntity targetTask = wkflTaskService.getById(operationVo.getTargetTaskId());
        WkflTaskEntity wkflTaskEntity = new WkflTaskEntity();
        wkflTaskEntity.setAssignee(targetTask.getAssignee());
        wkflTaskEntity.setSrcId(operationVo.getTaskId());
        copyTask(taskDelegate, wkflTaskEntity);
        wkflTaskEntity.setName(targetTask.getName());
        wkflTaskService.save(wkflTaskEntity);

        //将assignee移入候选人,统一使用候选模式
        taskDelegate.addCandidateUser(targetTask.getAssignee());
        taskDelegate.setAssignee(null);

        //自动转授权
        autoEntrust(wkflTaskEntity);
    }

    @Override
    public Set<String> getCandidates(String taskId) {
        List<IdentityLink> links = taskService.getIdentityLinksForTask(taskId);
        Set<String> candidates = new HashSet<>();
        for (IdentityLink link : links) {
            //有候选人
            if ("candidate".equals(link.getType()) && StringUtils.isNotBlank(link.getUserId())) {
                candidates.add(link.getUserId());
            }
            //有候选组
            if ("candidate".equals(link.getType()) && StringUtils.isNotBlank(link.getGroupId())) {
                List<User> users = identityService.createUserQuery().memberOfGroup(link.getGroupId()).list();
                for (User user : users) {
                    String userId = user.getId();
                    candidates.add(userId);
                }
            }
        }
        return candidates;
    }

    @Transactional
    @Override
    public String autoEntrust(WkflTaskEntity wkflTaskEntity) {
        //记录转授权起点任务信息
        String fromUserId = wkflTaskEntity.getAssignee();
        String fromTaskId = wkflTaskEntity.getId();
        for (int i = 0; i < 2; i++) {
            //TODO Call remote to Fetch entrust info by defKey and fromUserId
            String toUserId = "entrustee" + (i + 1);
            if (StringUtils.isBlank(toUserId) || fromUserId.equals(toUserId)) break;
            WkflTaskEntity fromTask = wkflTaskService.getById(fromTaskId);
            fromTask.setFinishTime(new Date());
            fromTask.setFinishType("entrusted");
            fromTask.setPhaseOpinion(fromUserId + "转授权给：" + toUserId);
            wkflTaskService.updateById(fromTask);

            WkflTaskEntity toTask = new WkflTaskEntity();
            BeanUtils.copyProperties(fromTask, toTask);
            toTask.setId(null);
            toTask.setSrcId(fromTask.getId());
            toTask.setAssignee(toUserId);
            toTask.setCreateTime(new Date());
            toTask.setFinishType(null);
            toTask.setFinishTime(null);
            toTask.setPhaseOpinion(null);
            wkflTaskService.save(toTask);
            fromUserId = toUserId;
            fromTaskId = toTask.getId();
        }
        //返回转授权后的最终任务
        return fromUserId;
    }

    @Override
    public Set<String> getAllowedBackTaskDefKeys(Set<String> allowedKeys, FlowNode flowNode, BpmnModelInstance bpmnModelInstance) {
        Collection<SequenceFlow> incomingFlows = flowNode.getIncoming();
        for (SequenceFlow sequenceFlow : incomingFlows) {
            String sourceId = sequenceFlow.getSource().getId();
            FlowNode preNode = bpmnModelInstance.getModelElementById(sourceId);
            if (preNode instanceof UserTask) {
                allowedKeys.add(sourceId);
            }
            if (preNode instanceof StartEvent) {
                return allowedKeys;
            }
            if (preNode instanceof EndEvent) {
                throw new RuntimeException("流程设计出错，结束节点在前面");
            }
            Set<String> taskDefKey = getAllowedBackTaskDefKeys(allowedKeys, preNode, bpmnModelInstance);
            allowedKeys.addAll(taskDefKey);
        }
        return allowedKeys;
    }

    @Override
    public boolean existUnfinishedFeedbackTasks(String taskId) {
        WkflTaskEntity wkflTaskEntity = wkflTaskService.getById(taskId);
        LambdaQueryWrapper<WkflTaskEntity> queryUnfinishedFeedbackTasks = new LambdaQueryWrapper<>();
        queryUnfinishedFeedbackTasks.eq(WkflTaskEntity::getRealTaskId, wkflTaskEntity.getRealTaskId());
        queryUnfinishedFeedbackTasks.like(WkflTaskEntity::getName, "[征求意见]");
        queryUnfinishedFeedbackTasks.isNull(WkflTaskEntity::getFinishTime);
        List<WkflTaskEntity> unfinishedFeedbackTasks = wkflTaskService.list(queryUnfinishedFeedbackTasks);
        if (!CollectionUtils.isEmpty(unfinishedFeedbackTasks)) {
            return true;
        }

        return false;
    }

    @Override
    public List<WkflTaskEntity> queryUnfinishedFeedbackTasks(String taskId) {
        WkflTaskEntity wkflTaskEntity = wkflTaskService.getById(taskId);
        LambdaQueryWrapper<WkflTaskEntity> queryUnfinishedFeedbackTasks = new LambdaQueryWrapper<>();
        queryUnfinishedFeedbackTasks.eq(WkflTaskEntity::getRealTaskId, wkflTaskEntity.getRealTaskId());
        queryUnfinishedFeedbackTasks.like(WkflTaskEntity::getName, "[征求意见]");
        queryUnfinishedFeedbackTasks.isNull(WkflTaskEntity::getFinishTime);
        List<WkflTaskEntity> unfinishedFeedbackTasks = wkflTaskService.list(queryUnfinishedFeedbackTasks);
        return unfinishedFeedbackTasks;
    }

    private void copyTask(DelegateTask taskDelegate, WkflTaskEntity wkflTaskEntity) {
        wkflTaskEntity.setId(null);
        wkflTaskEntity.setTenantId(taskDelegate.getTenantId());
        wkflTaskEntity.setRealTaskId(taskDelegate.getId());
        wkflTaskEntity.setTaskDefKey(taskDelegate.getTaskDefinitionKey());
        wkflTaskEntity.setProcDefId(taskDelegate.getProcessDefinitionId());
        wkflTaskEntity.setProcInstId(taskDelegate.getProcessInstanceId());
        wkflTaskEntity.setPriority(taskDelegate.getPriority());
        wkflTaskEntity.setExecutionId(taskDelegate.getExecutionId());
        wkflTaskEntity.setName(taskDelegate.getName());
        wkflTaskEntity.setCreateTime(taskDelegate.getCreateTime());
    }


}
